<?php
namespace app\common\util;

use Exception;

class Ai
{
	private static $model; // 当前使用的 AI 模型实例
	private static $modelConfig; // 当前模型的配置参数
	private static $apiUrl;			// API 请求的 URL
	private static $apiKey;			// 模型KEY
	private static $apiModel;		// 模型名称
	private static $apiParams=[];	// 模型参数
	private static $isInit = false; // 是否已经初始化

	/**
	 * 静态初始化方法，初始化 AI 模型和配置
	 */
	private static function init($setModel = null)
	{

		// 通过配置判断使用哪个 AI 模型
		$aiModelName = $setModel ?? env('ai.ai_name');
		
		// 初始化默认的 API 参数
		self::$apiParams = [
			'messages' => [
				[
					'role' => 'user',
					'content' => "",
				]
			],
		];
		
		// 初始化对应的 AI 模型和配置
		switch ($aiModelName) {
			case 'glm':
				self::$apiUrl = "http://open.bigmodel.cn/api/paas/v4/chat/completions";
				self::$apiKey = env('ai.glm_key');
				self::$apiModel = env('ai.glm_model');
				self::$apiParams['model'] = self::$apiModel;
				self::$apiParams['max_tokens'] = 4095;
				self::$apiParams['temperature'] = 0.7;
				break;
			case 'deepseek':
				self::$apiUrl = "https://api.deepseek.com/chat/completions";
				self::$apiKey = env('ai.deepseek_key');
				self::$apiModel = "deepseek-chat";
				self::$apiParams['model'] = self::$apiModel;
				self::$apiParams['stream'] = false;	// 非流式输出
				// self::$apiParams['messages'][] = [
				// 	'role' => 'system',
				// 	'content' => "You are a helpful assistant",
				// ];
				break;
			case 'hunyuan':
				self::$apiUrl = "https://api.hunyuan.cloud.tencent.com/v1/chat/completions";
				self::$apiKey = env('ai.hunyuan_key');
				self::$apiModel = env('ai.hunyuan_model');
				self::$apiParams['model'] = self::$apiModel;
				break;
            case 'siliconflow':
                self::$apiUrl = "https://api.siliconflow.cn/v1/chat/completions";
                self::$apiKey = env('ai.siliconflow_key');
                self::$apiModel = env('ai.siliconflow_model'); // 设置默认模型
                self::$apiParams['model'] = self::$apiModel;

                self::$apiParams['temperature'] = 0.1;     // 调整为前端配置的低随机性
                self::$apiParams['top_p'] = 0.9;           // 新增补全采样参数
                self::$apiParams['max_tokens'] = 512;      // 维持推荐值
                self::$apiParams['stream'] = false;        // 保持同步模式
                self::$apiParams['response_format']['type'] = 'text'; // 维持官方要求的输出格式
                
                // 移除冗余的 tools 参数
                break;
			default:
				return self::error("未配置或不支持的 AI 模型: {$aiModelName}");
		}
		
		self::$isInit= true;
	}

	/**
	 * 发送请求并格式化输出响应
	 * @param string $text 发送的内容
	 */
	public static function send($text,$backType='text'){
		// 初始化配置
		if(!self::$isInit) self::init();
		
		self::$apiParams['messages'][0]['content'] = $text;
	
		$result = self::sendPostRequest(self::$apiParams);
		
		// 格式化并打印响应
		// self::formatAndPrintResponse($result);
        
        if(!isset($result['choices'])){
            return self::error($result['msg']);
        }else{
            /// 解析响应
            $response=$result['choices'][0]['message']['content']??'';
            if ($response === null || $response === '') {
            	return self::error("接口无返回数据结果，请重试");
            }
        }

		switch ($backType) {
			case 'text':
				return $response;
				break;
			case 'json':
				$response = self::jsonToArray($response);
				if ($response === null) {
					return self::error("解析数据失败，请检查格式");
				}
				break;
			default:
				$response;
		}
		
        return ['code' => 0, 'data' => $response, 'msg'=>'获取成功'];
	}
	
	/**
	 * 发送 POST 请求
	 * @param array $data 请求的 JSON 数据
	 * @throws Exception 请求失败时抛出异常
	 */
	private static function sendPostRequest(array $data){
		$headers = [
			"Content-Type: application/json",
			"Authorization: Bearer " . self::$apiKey
		];
        
		$ch = curl_init();
		curl_setopt($ch, CURLOPT_URL, self::$apiUrl);
		curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
		curl_setopt($ch, CURLOPT_POST, true);
		curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
		curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
	
		$response = curl_exec($ch);
		$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
		curl_close($ch);
        
		if ($httpCode !== 200) {
			return self::error("HTTP error {$httpCode}: {$response}");
		}
		
		// 将 JSON 字符串解析为 PHP 数组
		$response = json_decode($response, true);

		return $response;
	}

	/**
	 * 将带有特殊标记的字符串内容解析为 PHP 数组
	 *
	 * @param string $rawString 原始字符串
	 * @return array|null 返回解析后的数组，若解析失败则返回 null
	 */
	private static function jsonToArray(string $rawString): ?array
	{
		// 1. 移除 """ 标记和换行符
        
		$cleanString = str_replace('"""', '', $rawString);

		// 2. 移除 ```json 和 ``` 标记
		$cleanString = str_replace(["```json", "```"], '', $cleanString);

		// 3. 修剪多余的空格和换行符
		$cleanString = trim($cleanString);

		// 4. 尝试将 JSON 字符串解析为 PHP 数组
		$data = json_decode($cleanString, true);

		// 5. 检查解析是否成功
		if (json_last_error() !== JSON_ERROR_NONE) {
			// 输出错误信息（可选）
			error_log("JSON 解析错误：" . json_last_error_msg());
			return null; // 解析失败，返回 null
		}

		return $data; // 返回解析后的数组
	}
	
	/**
	 * 格式化并打印响应
	 * @param string $responseText API 的原始响应
	 * @return void
	 */
	private static function formatAndPrintResponse(string $responseText)
	{
		$response = json_decode($responseText, true);
	
		if (!isset($response['choices'][0]['message']['content'])) {
			return self::error("Invalid API response: " . $responseText);
		}
	
		$messageContent = $response['choices'][0]['message']['content'];
		$formattedContent = self::formatContent($messageContent);
	
		// 格式化时间戳
		$timestamp = isset($response['created']) ? date('Y-m-d H:i:s', $response['created']) : 'Unknown';
	
		// 输出完整结果
		echo "Full API Response: {$responseText}\n";
		echo "AI Formatted Response:\n{$formattedContent} [{$timestamp}]\n";
	}
	
	/**
	 * 格式化内容以去除多余换行或修复列表格式
	 * @param string $content 原始内容
	 * @return string 格式化后的内容
	 */
	private static function formatContent(string $content): string
	{
		// 移除多余换行
		$content = preg_replace('/\n\n/', "\n", $content);
	
		// 修复编号列表格式（例如将 "\n1." 替换为 "\n1. "）
		$content = preg_replace('/\n(\d+)\./', "\n\$1. ", $content);
	
		return trim($content);
	}

	// 返回错误信息
	private static function error($msg){
		// abort(3001,$msg);
        return ['code'=>3001 , 'msg'=>$msg , 'data'=>[]];
	}
}
